package serial_handle

import (
	"data-system/common"
	"data-system/models"
	"data-system/tools"
	"encoding/json"
	"fmt"
	"log"
	"strings"

	"github.com/spf13/cast"
)

type jsonField struct {
	Name     string `json:"name"`
	Type     string `json:"type"`
	Required bool   `json:"required"`
}

type jsonEncode struct {
	Type   string            `json:"type"`
	Split  string            `json:"split"`
	Fields map[string]string `json:"fields"`
}

type jsonDecode struct {
	Type   string   `json:"type"`
	Join   string   `json:"join"`
	Fields []string `json:"fields"`
}

type SerialJsonArr1Ctx struct {
	models.SerialHandleCtx
}

func NewSerialJsonArr1Ctx(ctx models.SerialHandleCtx) (SerialHandler, error) {
	return &SerialJsonArr1Ctx{SerialHandleCtx: ctx}, nil
}

// Encode Excel数据 转 DB数据
func (ctx *SerialJsonArr1Ctx) Encode() (models.SerialHandleCtx, error) {
	if ctx.ExcelRow == nil {
		msg := fmt.Sprintf("【序列化-DefaultJson】【%v - %v - %v】行数据不能为空", ctx.Column.NodeType, ctx.Column.TbField, ctx.Column.Type)
		log.Printf(msg)
		return ctx.SerialHandleCtx, fmt.Errorf(msg)
	}
	if ctx.Column.Required && len(ctx.ExcelRow.Row[ctx.Column.TbField]) == 0 {
		msg := fmt.Sprintf("【序列化-DefaultJson】【%v - %v - %v】字段值不能为空", ctx.Column.NodeType, ctx.Column.TbField, ctx.Column.Type)
		log.Printf(msg)
		return ctx.SerialHandleCtx, fmt.Errorf(msg)
	}
	if len(ctx.ExcelRow.Row[ctx.Column.TbField]) > 0 {
		items := ctx.Column.Items.([]interface{})
		var encode jsonEncode
		bytes1, _ := json.Marshal(ctx.Column.Encode)
		err := json.Unmarshal(bytes1, &encode)
		if err != nil {
			msg := fmt.Sprintf("【序列化-DefaultJson】【%v - %v - %v】字段的encode字段解析失败：encode=%v",
				ctx.Column.NodeType, ctx.Column.TbField, ctx.Column.Type, ctx.Column.Decode)
			log.Println(msg)
			return ctx.SerialHandleCtx, fmt.Errorf(msg)
		}
		var result = make(map[string]interface{})
		excelOriginValue := cast.ToString(ctx.ExcelRow.Row[ctx.Column.TbField])
		values := strings.Split(excelOriginValue, encode.Split)
		for i, item := range items {
			var field jsonField
			tools.MapToObj(item.(map[string]interface{}), &field)
			encodeMap(field, cast.ToString(values[i]), result)
		}
		ctx.ResultData = result //map[string]map[string]interface{}{ctx.Column.Name: result}
	}
	return ctx.SerialHandleCtx, nil
}

func encodeMap(field jsonField, value string, result map[string]interface{}) map[string]interface{} {
	if len(value) > 0 {
		if field.Type == common.SerialTypeString {
			result[field.Name] = cast.ToString(value)
		} else if field.Type == common.SerialTypeNumber {
			originValue := cast.ToString(value)
			if len(originValue) > 0 {
				numberValue, _ := tools.StringToInt64(cast.ToString(value))
				result[field.Name] = numberValue
			}
		}
	}
	return result
}

// Decode DB数据 转 Excel数据
func (ctx *SerialJsonArr1Ctx) Decode() (models.SerialHandleCtx, error) {
	if ctx.DbRow == nil {
		msg := fmt.Sprintf("【反序列化-DefaultJson】【%v - %v - %v】行数据不能为空", ctx.Column.NodeType, ctx.Column.TbField, ctx.Column.Type)
		log.Println(msg)
		return ctx.SerialHandleCtx, fmt.Errorf(msg)
	}
	if ctx.Column.Required && ctx.DbRow.Data[ctx.Column.Name] == nil {
		msg := fmt.Sprintf("【反序列化-DefaultJson】【%v - %v - %v】字段值不能为空", ctx.Column.NodeType, ctx.Column.TbField, ctx.Column.Type)
		log.Println(msg)
		return ctx.SerialHandleCtx, fmt.Errorf(msg)
	}
	ctx.ResultData = ""
	if ctx.DbRow.Data[ctx.Column.Name] != nil {
		values := make([]string, 0)
		kv := tools.ObjToMap(ctx.DbRow.Data[ctx.Column.Name])
		items := ctx.Column.Items.([]interface{})
		for _, item := range items {
			column := item.(map[string]interface{})["name"]
			value := cast.ToString(kv[cast.ToString(column)])
			values = append(values, value)
		}
		var decode jsonDecode
		bytes1, _ := json.Marshal(ctx.Column.Decode)
		err := json.Unmarshal(bytes1, &decode)
		if err != nil {
			msg := fmt.Sprintf("【反序列化-DefaultJson】【%v - %v - %v】字段的decode字段解析失败：decode=%v",
				ctx.Column.NodeType, ctx.Column.TbField, ctx.Column.Type, ctx.Column.Decode)
			log.Println(msg)
			return ctx.SerialHandleCtx, fmt.Errorf(msg)
		}
		ctx.ResultData = strings.Join(values, decode.Join)
	}
	return ctx.SerialHandleCtx, nil
}
